package com.lqk.netty.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

public class MyServer {
    public static void main(String[] args) throws InterruptedException {

        // 创建两个线程组
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 因为是基于 Http 协议，使用 Http 的编码和解码器
                            pipeline.addLast(new HttpServerCodec());
                            // 以块方式写的，添加 ChunkedWriteHandler 处理器
                            pipeline.addLast(new ChunkedWriteHandler());
                            /*
                                说明：
                                    1. 因为 http 数据在传输过程中是分段的，HttpObjectAggregator 就是可以将多个段聚合起来
                                    2. 这就是为什么当浏览器发送大量数据时，就会发出多次 http 请求
                             */
                            pipeline.addLast(new HttpObjectAggregator(8192));

                            /*
                                说明：
                                1. 对于 webSocket，它的数据是以帧（frame）形式传递
                                2. 可以看到 WebSocketFrame 下面有六个子类
                                    * BinaryWebSocketFrame
                                    * CloseWebSocketFrame
                                    * ContinuationWebSocketFrame
                                    * PingWebSocketFrame
                                    * PongWebSocketFrame
                                    * TextWebSocketFrame
                                3. 浏览器请求时 ws://localhost:7000/hello 表示请求的 uri
                                4. WebSocketServerProtocolHandler 核心功能：将 Http 协议升级为 ws 协议（webSocket协议），保持长链接
                                5. 为什么 http 协议能够升级为 ws 协议？：是通过一个状态码 101 进行切换的
                             */
                            pipeline.addLast(new WebSocketServerProtocolHandler("/hello"));

                            // 自定义 Handler，处理业务逻辑
                            pipeline.addLast(new MyTextWebSocketFrameHandler());
                        }
                    });
            // 启动服务器
            ChannelFuture channelFuture = serverBootstrap.bind(17000).sync();
            channelFuture.channel().closeFuture().sync();

        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }

    }
}
